/*
==========================================================================

  ansic.y: PCYACC grammar description for ANSI C
  version 1.0
  by Xing Liu

  PCYACC (R) ABRAXAS SOFTWARE, ALL RIGHT RESERVED.

  Reference: The C Programming Language (Reference Manual)
             Second Edition
             By B.W. Kernighan and D.M. Retchie

===========================================================================
*/

%{

#include "protos.h"

extern void yyerror( char * );

%}

%union {
  int   i;
  float r;
  char *s;
}

/*----------------------- special symbols -------------------------------*/

%token DDD		/* three dots ... */

/*--------------------------- constants ---------------------------------*/

%token	CHARACTER_CONSTANT FLOAT_CONSTANT INTEGER_CONSTANT STRING

/*--------------------------- identifiers -------------------------------*/

%token	IDENTIFIER TYPENAME ENUMERATION_CONSTANT

/*--------------------------- key words ---------------------------------*/

%token	Auto		Break		Case		Char		Const
%token	Continue	Default		Do  	 	Double		Else
%token	Enum		Extern 		Float		For		Goto
%token	If		Int  	  	Long	 	Register	Return
%token	Short		Signed 		Sizeof	 	Static		Struct
%token	Switch		Typedef		Void 	  	Volatile	Union
%token	Unsigned	While

/*--------------------------- combined operators ------------------------*/

/* binary logicals and comparators */

%token	OROR	ANDAND	EQU	NEQ	LEQ	GEQ

/* shift operators */						

%token	SHL	SHR

/* unary increments */

%token	ADDADD	SUBSUB

/* pointer */

%token	PTR

/* assignments */

%token	ADDEQ	SUBEQ	MULEQ	DIVEQ	MODEQ
%token	SHLEQ	SHREQ	ANDEQ	XOREQ	IOREQ

/*--------------------------- operator precedence -----------------------*/

/* comma operator */

%left	','

/* assignment operators */

%right	ADDEQ	SUBEQ	MULEQ	DIVEQ	MODEQ
	SHLEQ	SHREQ	BANDEQ	BXOREQ	BOREQ

/* binary operators */

%right	'?'	':'
%left	OROR
%left	ANDAND
%left	BOR
%left	BEOR
%left	BAND
%left	EQU
%left	NEQ
%left	LEQ	GEQ
%left	SHL	SHR
%left	ADD	SUB
%left	MUL	DIV	MOD

/* unary operators */

%right	ADDADD	SUBSUB	'~'	'!'
	UNIADD	UNISUB	UNIMUL	UNIBAND
	Sizeof	'*'

/* special operators */

%left	'('	'['	'.'	PTR

/*--------------------------- start symbol ------------------------------*/

%start translation_unit

%%

translation_unit
  : external_declaration
      { printf("translation_unit\n"); }
  | translation_unit external_declaration
      { printf("translation_unit\n"); }
  ;

external_declaration
  : function_definition 
      { printf("external_declaration\n"); }
  | declaration
      { printf("external_declaration\n"); }
  ;

function_definition
  : declaration_specifiers declarator declaration_list compound_statement
      { printf("function_definition\n"); }
  | declaration_specifiers declarator                  compound_statement
      { printf("function_definition\n"); }
  |                        declarator declaration_list compound_statement
      { printf("function_definition\n"); }
  |                        declarator                  compound_statement
      { printf("function_definition\n"); }
  ;

declaration
  : declaration_specifiers init_declarator_list ';'
      { printf("declaration\n"); }
  | declaration_specifiers                      ';'
      { printf("declaration\n"); }
  ;

declaration_list
  : declaration
      { printf("declaration_list\n"); }
  | declaration_list declaration
      { printf("declaration_list\n"); }
  ;

declaration_specifiers
  : declaration_specifier
      { printf("declaration_specifiers\n"); }
  | declaration_specifiers declaration_specifier
      { printf("declaration_specifiers\n"); }
  ;

declaration_specifier
  : storage_class_specifier
      { printf("declaration_specifier\n"); }
  | type_specifier
      { printf("declaration_specifier\n"); }
  | type_qualifier
      { printf("declaration_specifier\n"); }
  ;

storage_class_specifier
  : Auto
      { printf("storage_class_specifier\n"); }
  | Extern
      { printf("storage_class_specifier\n"); }
  | Register
      { printf("storage_class_specifier\n"); }
  | Static
      { printf("storage_class_specifier\n"); }
  | Typedef		/* need to insert type names into symbols table */
      { printf("storage_class_specifier\n"); }
  ;

type_specifier
  : Char
      { printf("type_specifier\n"); }
  | Double
      { printf("type_specifier\n"); }
  | Float
      { printf("type_specifier\n"); }
  | Int
      { printf("type_specifier\n"); }
  | Long
      { printf("type_specifier\n"); }
  | Short
      { printf("type_specifier\n"); }
  | Signed
      { printf("type_specifier\n"); }
  | Unsigned
      { printf("type_specifier\n"); }
  | Void
      { printf("type_specifier\n"); }
  | TYPENAME
      { printf("type_specifier\n"); }
  | aggregate_specifier
      { printf("type_specifier\n"); }
  ;

type_qualifier
  : Const
      { printf("type_qualifier\n"); }
  | Volatile
      { printf("type_qualifier\n"); }
  ;

aggregate_specifier
  : aggregate_type IDENTIFIER '{' aggregate_member_list '}'
      { printf("aggregate_specifier\n"); }
  | aggregate_type            '{' aggregate_member_list '}'
      { printf("aggregate_specifier\n"); }
  | aggregate_type IDENTIFIER
      { printf("aggregate_specifier\n"); }
  ;

aggregate_type
  : Enum
      { printf("aggregate_type\n"); }
  | Struct
      { printf("aggregate_type\n"); }
  | Union
      { printf("aggregate_type\n"); }
  ;

aggregate_member_list
  : struct_declaration_list
      { printf("aggregate_member_list\n"); }
  | enumerator_list
      { printf("aggregate_member_list\n"); }
  ;

struct_declaration_list
  : struct_declaration
      { printf("struct_declaration_list\n"); }
  | struct_declaration_list struct_declaration
      { printf("struct_declaration_list\n"); }
  ;

init_declarator_list
  : init_declarator
      { printf("init_declarator_list\n"); }
  | init_declarator_list ',' init_declarator
      { printf("init_declarator_list\n"); }
  ;

init_declarator
  : declarator
      { printf("init_declarator\n"); }
  | declarator '=' initializer
      { printf("init_declarator\n"); }
  ;

struct_declaration
  : declaration_specifiers struct_declarator_list ';'
      { printf("struct_declaration\n"); }
  ;

struct_declarator_list
  : struct_declarator
      { printf("struct_declarator_list\n"); }
  | struct_declarator_list ',' struct_declarator
      { printf("struct_declarator_list\n"); }
  ;

struct_declarator
  : declarator
      { printf("struct_declarator\n"); }
  | declarator ':' constant_expression
      { printf("struct_declarator\n"); }
  |            ':' constant_expression
      { printf("struct_declarator\n"); }
  ;

enumerator_list
  : enumerator
      { printf("enumerator_list\n"); }
  | enumerator_list ',' enumerator
      { printf("enumerator_list\n"); }
  ;

enumerator		/* need to insert enumeration names into symbol table */
  : IDENTIFIER
      { printf("enumerator\n"); }
  | IDENTIFIER '=' constant_expression
      { printf("enumerator\n"); }
  ;

declarator
  : pointer direct_declarator
      { printf("declarator\n"); }
  |         direct_declarator
      { printf("declarator\n"); }
  ;

direct_declarator
  : IDENTIFIER
      { printf("direct_declarator\n"); }
  | '(' declarator ')' 
      { printf("direct_declarator\n"); }
  | direct_declarator '[' constant_expression ']'
      { printf("direct_declarator\n"); }
  | direct_declarator '['                     ']'
      { printf("direct_declarator\n"); }
  | direct_declarator '(' parameter_type_list ')'
      { printf("direct_declarator\n"); }
  | direct_declarator '(' identifier_list     ')'
      { printf("direct_declarator\n"); }
  | direct_declarator '('                     ')'
      { printf("direct_declarator\n"); }
  ;

pointer
  : '*' type_qualifier_list
      { printf("pointer\n"); }
  | '*'
      { printf("pointer\n"); }
  | '*' type_qualifier_list pointer
      { printf("pointer\n"); }
  | '*'                     pointer
      { printf("pointer\n"); }
  ;

type_qualifier_list
  : type_qualifier
      { printf("type_qualifier_list\n"); }
  | type_qualifier_list type_qualifier
      { printf("type_qualifier_list\n"); }
  ;

parameter_type_list
  : parameter_list
      { printf("parameter_type_list\n"); }
  | parameter_list ',' DDD
      { printf("parameter_type_list\n"); }
  ;

parameter_list
  : parameter_declaration
      { printf("parameter_list\n"); }
  | parameter_list ',' parameter_declaration
      { printf("parameter_list\n"); }
  ;

parameter_declaration
  : declaration_specifiers declarator
      { printf("parameter_declaration\n"); }
  | declaration_specifiers abstract_declarator
      { printf("parameter_declaration\n"); }
  | declaration_specifiers
      { printf("parameter_declaration\n"); }
  ;

identifier_list
  : IDENTIFIER
      { printf("identifier_list\n"); }
  | identifier_list ',' IDENTIFIER
      { printf("identifier_list\n"); }
  ;

initializer
  : assignment_expression
      { printf("initializer\n"); }
  | '{' initializer_list '}'
      { printf("initializer\n"); }
  | '{' initializer_list ',' '}'
      { printf("initializer\n"); }
  ;

initializer_list
  : initializer
      { printf("initializer_list\n"); }
  | initializer_list ',' initializer
      { printf("initializer_list\n"); }
  ;

type_name
  : declaration_specifiers abstract_declarator
      { printf("type_name\n"); }
  | declaration_specifiers
      { printf("type_name\n"); }
  ;

abstract_declarator
  : pointer
      { printf("abstract_declarator\n"); }
  | pointer direct_abstract_declarator
      { printf("abstract_declarator\n"); }
  |         direct_abstract_declarator
      { printf("abstract_declarator\n"); }
  ;

direct_abstract_declarator
  : '(' abstract_declarator ')'
      { printf("direct_abstract_declarator\n"); }
  | direct_abstract_declarator '[' constant_expression ']'
      { printf("direct_abstract_declarator\n"); }
  | direct_abstract_declarator '['                     ']'
      { printf("direct_abstract_declarator\n"); }
  |                            '[' constant_expression ']'
      { printf("direct_abstract_declarator\n"); }
  |                            '['                     ']'
      { printf("direct_abstract_declarator\n"); }
  | direct_abstract_declarator '(' parameter_type_list ')'
      { printf("direct_abstract_declarator\n"); }
  | direct_abstract_declarator '('                     ')'
      { printf("direct_abstract_declarator\n"); }
  |                            '(' parameter_type_list ')'
      { printf("direct_abstract_declarator\n"); }
  |                            '('                     ')'
      { printf("direct_abstract_declarator\n"); }
  ;

statement
  : labeled_statement
      { printf("statement\n"); }
  | expression_statement
      { printf("statement\n"); }
  | compound_statement
      { printf("statement\n"); }
  | selection_statement
      { printf("statement\n"); }
  | iteration_statement
      { printf("statement\n"); }
  | jump_statement
      { printf("statement\n"); }
  ;

labeled_statement
  : IDENTIFIER ':' statement
      { printf("labeled_statement\n"); }
  | Case constant_expression ':' statement
      { printf("labeled_statement\n"); }
  | Default ':' statement
      { printf("labeled_statement\n"); }
  ;

expression_statement
  : expression ';'
      { printf("expression_statement\n"); }
  |            ';'
      { printf("expression_statement\n"); }
  ;

compound_statement
  : '{' declaration_list statement_list '}'
      { printf("compound_statement\n"); }
  | '{' declaration_list                '}'
      { printf("compound_statement\n"); }
  | '{'                  statement_list '}'
      { printf("compound_statement\n"); }
  | '{'                                 '}'
      { printf("compound_statement\n"); }
  ;

statement_list
  : statement
      { printf("statement_list\n"); }
  | statement_list statement
      { printf("statement_list\n"); }
  ;

selection_statement
  : If '(' expression ')' statement
      { printf("selection_statement\n"); }
  | If '(' expression ')' statement Else statement
      { printf("selection_statement\n"); }
  | Switch '(' expression ')' statement
      { printf("selection_statement\n"); }
  ;

iteration_statement
  : While '(' expression ')' statement
      { printf("iteration_statement\n"); }
  | Do statement While '(' expression ')' ';'
      { printf("iteration_statement\n"); }
  | For '(' expression ';' expression ';' expression ')' statement
      { printf("iteration_statement\n"); }
  | For '(' expression ';' expression ';'            ')' statement
      { printf("iteration_statement\n"); }
  | For '(' expression ';'            ';' expression ')' statement
      { printf("iteration_statement\n"); }
  | For '(' expression ';'            ';'            ')' statement
      { printf("iteration_statement\n"); }
  | For '('            ';' expression ';' expression ')' statement
      { printf("iteration_statement\n"); }
  | For '('            ';' expression ';'            ')' statement
      { printf("iteration_statement\n"); }
  | For '('            ';'            ';' expression ')' statement
      { printf("iteration_statement\n"); }
  | For '('            ';'            ';'            ')' statement
      { printf("iteration_statement\n"); }
  ;

jump_statement
  : Goto IDENTIFIER   ';'
      { printf("jump_statement\n"); }
  | Continue          ';'
      { printf("jump_statement\n"); }
  | Break             ';'
      { printf("jump_statement\n"); }
  | Return expression ';'
      { printf("jump_statement\n"); }
  | Return            ';'
      { printf("jump_statement\n"); }
  ;

expression
  : assignment_expression
      { printf("expression\n"); }
  | expression ',' assignment_expression
      { printf("expression\n"); }
  ;

assignment_expression
  : conditional_expression
      { printf("assignment_expression\n"); }
  | unary_expression assignment_operator assignment_expression
      { printf("assignment_expression\n"); }
  ;

assignment_operator
  : '='
      { printf("assignment_operator\n"); }
  | MULEQ
      { printf("assignment_operator\n"); }
  | DIVEQ
      { printf("assignment_operator\n"); }
  | MODEQ
      { printf("assignment_operator\n"); }
  | ADDEQ
      { printf("assignment_operator\n"); }
  | SUBEQ
      { printf("assignment_operator\n"); }
  | SHLEQ
      { printf("assignment_operator\n"); }
  | SHREQ
      { printf("assignment_operator\n"); }
  | ANDEQ
      { printf("assignment_operator\n"); }
  | IOREQ
      { printf("assignment_operator\n"); }
  | XOREQ
      { printf("assignment_operator\n"); }
  ;

conditional_expression
  : logical_or_expression
      { printf("conditional_expression\n"); }
  | logical_or_expression '?' expression ':' conditional_expression
      { printf("conditional_expression\n"); }
  ;

constant_expression
  : conditional_expression
      { printf("constant_expression\n"); }
  ;

logical_or_expression
  : logical_and_expression
      { printf("logical_or_expression\n"); }
  | logical_or_expression OROR logical_and_expression
      { printf("logical_or_expression\n"); }
  ;

logical_and_expression
  : inclusive_or_expression
      { printf("logical_and_expression\n"); }
  | logical_and_expression ANDAND inclusive_or_expression
      { printf("logical_and_expression\n"); }
  ;

inclusive_or_expression
  : exclusive_or_expression
      { printf("inclusive_or_expression\n"); }
  | inclusive_or_expression '|' exclusive_or_expression
      { printf("inclusive_or_expression\n"); }
  ;

exclusive_or_expression
  : and_expression
      { printf("exclusive_or_expression\n"); }
  | exclusive_or_expression '^' and_expression
      { printf("exclusive_or_expression\n"); }
  ;

and_expression
  : equality_expression
      { printf("and_expression\n"); }
  | and_expression '&' equality_expression
      { printf("and_expression\n"); }
  ;

equality_expression
  : relational_expression
      { printf("equality_expression\n"); }
  | equality_expression EQU  relational_expression
      { printf("equality_expression\n"); }
  | equality_expression NEQ relational_expression
      { printf("equality_expression\n"); }
  ;

relational_expression
  : shift_expression
      { printf("relational_expression\n"); }
  | relational_expression '<' shift_expression
      { printf("relational_expression\n"); }
  | relational_expression '>' shift_expression
      { printf("relational_expression\n"); }
  | relational_expression LEQ shift_expression
      { printf("relational_expression\n"); }
  | relational_expression GEQ shift_expression
      { printf("relational_expression\n"); }
  ;
			     
shift_expression
  : additive_expression
      { printf("shift_expression\n"); }
  | shift_expression SHL additive_expression
      { printf("shift_expression\n"); }
  | shift_expression SHR additive_expression
      { printf("shift_expression\n"); }
  ;

additive_expression
  : multiplicative_expression
      { printf("additive_expression\n"); }
  | additive_expression '+' multiplicative_expression
      { printf("additive_expression\n"); }
  | additive_expression '-' multiplicative_expression
      { printf("additive_expression\n"); }
  ; 

multiplicative_expression
  : cast_expression
      { printf("multiplicative_expression\n"); }
  | multiplicative_expression '*' cast_expression
      { printf("multiplicative_expression\n"); }
  | multiplicative_expression '/' cast_expression
      { printf("multiplicative_expression\n"); }
  | multiplicative_expression '%' cast_expression
      { printf("multiplicative_expression\n"); }
  ; 

cast_expression
  : unary_expression
      { printf("cast_expression\n"); }
  | '(' type_name ')' cast_expression
      { printf("cast_expression\n"); }
  ;

unary_expression
  : postfix_expression
      { printf("unary_expression\n"); }
  | ADDADD unary_expression
      { printf("unary_expression\n"); }
  | SUBSUB unary_expression
      { printf("unary_expression\n"); }
  | unary_operator cast_expression
      { printf("unary_expression\n"); }
  | Sizeof unary_expression
      { printf("unary_expression\n"); }
  | Sizeof '(' type_name ')'
      { printf("unary_expression\n"); }
  ;

unary_operator
  : '&'
      { printf("unary_operator\n"); }
  | '*'
      { printf("unary_operator\n"); }
  | '+'
      { printf("unary_operator\n"); }
  | '-'
      { printf("unary_operator\n"); }
  | '~'
      { printf("unary_operator\n"); }
  | '!'
      { printf("unary_operator\n"); }
  ;

postfix_expression
  : primary_expression
      { printf("postfix_expression\n"); }
  | postfix_expression '[' expression ']'
      { printf("postfix_expression\n"); }
  | postfix_expression '(' argument_expression_list ')'
      { printf("postfix_expression\n"); }
  | postfix_expression '('                          ')'
      { printf("postfix_expression\n"); }
  | postfix_expression '.' IDENTIFIER
      { printf("postfix_expression\n"); }
  | postfix_expression PTR IDENTIFIER
      { printf("postfix_expression\n"); }
  | postfix_expression ADDADD
      { printf("postfix_expression\n"); }
  | postfix_expression SUBSUB
      { printf("postfix_expression\n"); }
  ;

primary_expression
  : IDENTIFIER
      { printf("primary_expression\n"); }
  | constant
      { printf("primary_expression\n"); }
  | STRING
      { printf("primary_expression\n"); }
  | '(' expression ')'
      { printf("primary_expression\n"); }
  ;

argument_expression_list
  : assignment_expression
      { printf("argument_expression_list\n"); }
  | argument_expression_list ',' assignment_expression
      { printf("argument_expression_list\n"); }
  ;

constant
  : INTEGER_CONSTANT
      { printf("constant\n"); }
  | CHARACTER_CONSTANT
      { printf("constant\n"); }
  | FLOAT_CONSTANT
      { printf("constant\n"); }
  | ENUMERATION_CONSTANT
      { printf("constant\n"); }
  ;

